﻿using System;
using System.Collections.Generic;
using System.Xml.Linq;

namespace TemplateFoundation.Feeds
{
    /// <summary>
    /// Used to create an RSS feed
    /// </summary>
    /// <seealso cref="RssItem"/>
    /// <seealso cref="RssItemCollection"/>
    public class RssChannel
    {
        private XDocument _xml;
     
        /// <summary>
        /// Creates a new RSS channel for creating an RSS feed
        /// </summary>
        /// <param name="title"></param>
        /// <param name="link"></param>
        /// <param name="description"></param>
        public RssChannel(string title, string link, string description)
        {
            Title = title;
            Link = link;
            Description = description;
            Items=new RssItemCollection();
        }

        #region Public members

        /// <summary>
        /// Gets or sets the channel title
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// Gets or sets the channel link
        /// </summary>
        public string Link { get; set; }

        /// <summary>
        /// Gets or sets the channel description
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// Gets or sets the feed generator name
        /// </summary>
        public string Generator { get; set; }

        /// <summary>
        /// Gets or sets the language of the feed
        /// </summary>
        public string Language { get; set; }

        /// <summary>
        /// Gets or sets the Docs property
        /// </summary>
        public string Docs { get; set; }

        /// <summary>
        /// Gets or sets the list of RSS items to include in the feed
        /// </summary>
        public RssItemCollection Items { get; set; }
        
        /// <summary>
        /// Add a new RSS item to the feed
        /// </summary>
        /// <param name="item"></param>
        /// <param name="skipLanguageCheck"></param>
        public void AddItem(RssItem item, bool skipLanguageCheck)
        {
            if (!string.IsNullOrEmpty(Language) && !skipLanguageCheck)
            {
                if(item.Language!=Language)
                {
                    throw new ArgumentException("The specified RSS item's language differs from the channel language, use overload to skip language check");
                }
            }

            Items.Add(item);
        }

        /// <summary>
        /// Add a new RSS item to the feed
        /// </summary>
        public void AddItem(RssItem item)
        {
            AddItem(item,false);
        }

        /// <summary>
        /// Add a new RSS item to the feed
        /// </summary>
        public void AddItem(IEnumerable<RssItem> items)
        {
            foreach(RssItem item in items)
            {
                AddItem(item);
            }
        }

        /// <summary>
        /// Gets the RSS XML for the channel and its items
        /// </summary>
        public virtual XDocument Xml
        {
            get
            {
                if (_xml==null)
                {
                    _xml = new XDocument(
                        new XDeclaration("1.0", "utf-8", "yes"),
                        new XElement("rss",
                                     new XAttribute("version", "2.0"),
                                     new XElement("channel", CreateElements())));
                }

                return _xml;
            }
        }

        #endregion

        #region Helper methods

        /// <summary>
        /// Creates the RSS elements for the channel.
        /// </summary>
        /// <returns></returns>
        protected virtual IEnumerable<XElement> CreateElements()
        {
            var feed = new List<XElement>();

            if (!string.IsNullOrEmpty(Title))
            {
                feed.Add(new XElement("title", Title));
            }

            if (!string.IsNullOrEmpty(Link))
            {
                feed.Add(new XElement("link", Link));
            }

            if (!string.IsNullOrEmpty(Description))
            {
                feed.Add(new XElement("description", Description));
            }

            if (!string.IsNullOrEmpty(Generator))
            {
                feed.Add(new XElement("generator", Generator));
            }

            // Add XML for each RSS item
            foreach (var item in Items)
            {
                var itemElement = new XElement("item");

                itemElement.Add(new XElement("title", item.Title));
                itemElement.Add(new XElement("description", item.Description));
                itemElement.Add(new XElement("link", item.Link));
                itemElement.Add(new XElement("pubDate", GetDateTimeString(item.Date)));

                foreach (var c in item.Categories)
                {
                    itemElement.Add(new XElement("category", c));
                }  

                feed.Add(itemElement);
            }

            return feed;
        }

        /// <summary>
        /// Gets the DateTime string used for dates in RSS feed
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        protected virtual string GetDateTimeString(DateTime time)
        {
            // Currently returning a string conforming to RFC822

            string[] months =
            {
                "Jan",
                "Feb",
                "Mar",
                "Apr",
                "May",
                "Jun",
                "Jul",
                "Aug",
                "Sep",
                "Oct",
                "Nov",
                "Dec"
            };

            return string.Format("{0}, {1} {2} {3} {4} +{5}{6}",
                                         time.DayOfWeek.ToString().Substring(0, 3),
                                         time.ToString("dd"),
                                         months[time.Month-1],
                                         time.ToString("yyyy"),
                                         time.ToString("HH:mm:ss"),
                                         TimeZoneInfo.Local.BaseUtcOffset.Hours.ToString("00"),
                                         TimeZoneInfo.Local.BaseUtcOffset.Minutes.ToString("00"));
        }

        #endregion
    }
}
